#include <iostream>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <algorithm>
#include <assert.h>

using namespace std;

#define DBG(X) if (debug) cerr << #X << " = " << X << endl;
#define DBGComment(String) if (debug) cerr << #String << endl;
#define DBGAssert(ExpresionBooleana) if (debug && ExpresionBooleana) cerr << #ExpresionBooleana << " ? " << false << endl;
#define DBGMat(M, sizeX, sizeY) if(debug){ cerr << #M << " = " << endl; forn(x, (sizeX)) { forn(y, (sizeY)) cerr << "\t" << M[x][y]; cerr << endl;}}
#define DBGAssert(A) if(debug_assert) { assert((A)); }

#define forn( i,n ) for ( int i=0; i<(int)(n); i++ )
// forn : for ( i en [0,n) )
#define fornin(i, desde, hasta) for ( int i=(desde); i<(int)(hasta); i++ )
// fornin : for ( i en [desde,hasta) )
#define decl(v, c) typeof(c) v = c
// decl : Declara la variable v igual que c
#define forall(i, c) for(decl(i, c.begin()); i!=c.end(); ++i)
// forall : foreach( i in c)
#define forallDist(i, j , c) for(decl(i, c.begin()); ((++i)--) != c.end(); i++) for(decl(j, ((++i)--)); j != c.end(); j++)
// forall : foreach( i,j in c) talque i != j

typedef pair<int, string > nodo;
typedef vector< nodo > recorridos;
typedef set< nodo > nodos;
typedef map< nodo, int > posiciones;
typedef pair<int, int> respuesta;
typedef vector< respuesta > respuestas;
typedef vector< bool > vbool;

bool debug = false;
bool debug_assert =false;
char caracter_extra;
int infinito = 1000000;
int un_dia = 1440;

string int2string(int n)
{
    stringstream flujo;
    flujo << n;
    return flujo.str();
}

string minutos(int tiempo)
{
    int min = tiempo % 60;
    if(min > 9)
        return int2string(min);
    else
        return "0"+ int2string(min);
}

string horasFormated(int tiempo)
{
    int min = tiempo % 60;
    int h = (tiempo - min ) / 60;
    if(h > 9)
        return "" + int2string(h);
    else
        return "0"+ int2string(h);
}

string horasNoFormated(int tiempo)
{
    int min = tiempo % 60;
    int h = (tiempo - min) / 60;
    return int2string(h);

}

string tiempoFormated(int tiempo)
{
    return horasFormated(tiempo) + ":" + minutos(tiempo);
}

string tiempoNoFormated(int tiempo)
{
    return horasNoFormated(tiempo) + ":" + minutos(tiempo);
}

int posicionDe(int i, string s, posiciones &las_pos)
{
    return las_pos[nodo(i,s)];
}

void ResolverUnCaso()
{
    int cant_recorridos = 0;
    int cant_estaciones = 0;
    int tiempo_actual = 0;
    int horas, minutos;

    string ciudad, desde, hasta;

    /** Levanto los datos de entrada **/
    cin >> cant_recorridos;

    recorridos los_recorridos[cant_recorridos];   // Un Diccionario de recorridos
    nodos los_nodos;                    // Todos los nodos ( un nodo es un par Ciudad Horario )
    posiciones las_posiciones;          // Algo que mapea Cada Nodo a un int (posicion en la matriz)
    vbool es_estacion_primera;          // Me fijo si es la primera estacion.

    int posicion_nodo = 0;
    forn(un_recorrido, cant_recorridos) // Para cada recorrido
    {
        cin >> cant_estaciones;
        tiempo_actual = 0;
        bool es_primera = true;
        forn(una_estacion, cant_estaciones) // Para cada estacion en un recorrido
        {
            cin >> horas >> caracter_extra >> minutos >> ciudad;
            int duracion_viaje = horas * 60 + minutos;
            DBGAssert(duracion_viaje >= 0);
            tiempo_actual += duracion_viaje;  // Obtengo el tiempo actual de esta estacion.

            nodo un_nodo = nodo(tiempo_actual%un_dia, ciudad);         // Creo el nodo Ciudad Horario
            los_recorridos[un_recorrido].push_back(nodo(tiempo_actual, ciudad));   // Guardo esta ciudad en el recorrido.
            if(las_posiciones.find(un_nodo) == las_posiciones.end()) // Si el nodo no existe!
            {
                los_nodos.insert(un_nodo);  // Guardo el nodo
                las_posiciones[un_nodo] = posicion_nodo; // Guardo la posicion del nodo
                es_estacion_primera.assign(posicion_nodo, es_primera); // Guardo si es primera estacion
                es_primera = false;
                posicion_nodo++;
            }
        }
    }

    cin >> desde >> hasta; // Obtengo la el origen y destino.

    /** Fin levantar datos **/

    // Creo la matriz de aydacencia de los nodos y la inicalizo en infinito
    int cantidad_nodos = los_nodos.size();
    int matriz_ady[cantidad_nodos][cantidad_nodos];
    forn(x, cantidad_nodos) forn(y, cantidad_nodos)
        matriz_ady[x][y] = infinito;

    /** Inicializo la matriz de ady con el tiempo entre recorridos **/

    DBG(cantidad_nodos);
    forn(un_recorrido, cant_recorridos) // Para cada recorrido
    {
        forall(una_estacion, los_recorridos[un_recorrido]) // Para cada estacion
        {
            DBG(una_estacion->first);
            DBG(una_estacion->second);
            decl(siguiente_estacion, ++una_estacion); // Busco la siguiente estacion
            if(siguiente_estacion!=los_recorridos[un_recorrido].end()) // Si existe la siguiente estacion
            {
                DBG(siguiente_estacion->first);
                DBG(siguiente_estacion->second);
                una_estacion--;
                int diferencia = siguiente_estacion->first - una_estacion->first;// Obtengo el tiempo entre una y otra
                DBG(diferencia);
                int pos_una_estacion        = posicionDe(una_estacion->first % un_dia   , una_estacion->second, las_posiciones);
                int pos_siguiente_estacion  = posicionDe(siguiente_estacion->first % un_dia, siguiente_estacion->second, las_posiciones);
                matriz_ady[pos_una_estacion][pos_siguiente_estacion] = diferencia; // Modifico el tiempo entre las estaciones
            }
            else
                break;
        }
    }

    /** Inicializo la matriz de ady con el tiempo "muerto" en una misma ciudad **/

    forallDist(i,j, los_nodos) // Para todo par de nodos
    {
        if(i->second == j->second) // Si es la misma ciudad
        {
            int pos_i = las_posiciones[nodo(i->first, i->second)];
            int pos_j = las_posiciones[nodo(j->first, j->second)];
            int diferencia_i_a_j = (j->first - i->first ); // Obtengo el tiempo entre una y otra
            int diferencia_j_a_i = un_dia - (diferencia_i_a_j % un_dia);
            DBGAssert(diferencia_i_a_j >= 0);
            DBGAssert(diferencia_i_a_j < un_dia);
            DBGAssert(diferencia_j_a_i >= 0);
            if(!es_estacion_primera[pos_i])                  // A menos que sea estacion inicial
                matriz_ady[pos_i][pos_j] = diferencia_i_a_j; // Actualizo la matriz ya que puedo quedarme ahi.
            if(!es_estacion_primera[pos_j])                  // A menos que sea estacion incial
                matriz_ady[pos_j][pos_i] = diferencia_j_a_i; // Actualizo ya que puedo pasar el dia.
        }
    }

    /** Inicializo la matriz de ady con el tiempo entre un nodo y si mismo en 0 **/

    forn(x, cantidad_nodos)
        matriz_ady[x][x] = 0;


    DBGMat(matriz_ady, cantidad_nodos, cantidad_nodos);

    if(debug) forn(x, cantidad_nodos) forn(y, cantidad_nodos)
        DBGAssert(matriz_ady[x][y] >= 0);

    /** Calculo el camino minimo entre todo par de nodos **/
    forn(k, cantidad_nodos) forn(i, cantidad_nodos) forn(j, cantidad_nodos)
        matriz_ady[i][j] = min ( matriz_ady[i][j], matriz_ady[i][k]+matriz_ady[k][j] );

    DBGMat(matriz_ady, cantidad_nodos, cantidad_nodos);

    if(debug) forn(x, cantidad_nodos) forn(y, cantidad_nodos)
        DBGAssert(matriz_ady[x][y] >= 0);

    /** Calculo todas las formas de ir de uno a otro **/
    int tiempo_anterior = -1;
    respuestas las_respuestas;

    //DBG(cantidad_nodos);
    forall(d, los_nodos)
    {
        DBG(d->second);
        if(d->second == desde)
        {
            DBG(d->first);
            if(tiempo_anterior != d->first)
            {
                int minimo = infinito;

                forall(h, los_nodos)
                {
                    DBG(h->second);
                    if(h->second == hasta)
                    {
                        int p_x = las_posiciones[nodo(d->first, d->second)];
                        int p_y = las_posiciones[nodo(h->first, h->second)];
                        int tiempo_llegada = matriz_ady[p_x][p_y];
                        if(minimo > tiempo_llegada)
                        {
                            DBG(tiempo_llegada);
                            minimo = tiempo_llegada;
                        }
                    }

                }
                if(minimo < infinito)
                {
                    tiempo_anterior = d->first;
                    las_respuestas.push_back(respuesta(((d->first)%un_dia), minimo));
                }
            }
        }
    }

    /** Obtengo dentro de todas las posibilidades las validas **/
    respuestas las_respuestas_invalidas;
    forallDist(i, j, las_respuestas)
    {
        if  (
            i->first < j->first &&
            (i->first + i->second) >= (j->first + j->second)
            )
        {
            las_respuestas_invalidas.push_back(respuesta(i->first, i->second));
        }

        if  (
            j->first < i->first &&
            (j->first + j->second) >= (i->first + i->second)
            )
        {
            las_respuestas_invalidas.push_back(respuesta(j->first, j->second));
        }

        if  (
            i->first < j->first + un_dia&&
            (i->first + i->second) >= (j->first + j->second) + un_dia
            )
        {
            las_respuestas_invalidas.push_back(respuesta(i->first, i->second));
        }

        if  (
            j->first < i->first + un_dia &&
            (j->first + j->second) >= (i->first + i->second) + un_dia
            )
        {
            las_respuestas_invalidas.push_back(respuesta(j->first, j->second));
        }

    }

    DBGAssert(las_respuestas.size() - las_respuestas_invalidas.size() > 0);
    /** Muestro los resultados validos **/

    forall(i, las_respuestas)
    {
        bool esta = false;
        forall(j, las_respuestas_invalidas)
        {
            if(j->first == i->first && j->second == i->second)
            {
                esta = true;
                break;
            }
        }
        if(!esta)
        {
            DBGAssert(i->first < un_dia);
            DBGAssert(i->first >= 0);
            DBGAssert(i->second >= 0);
            cout << tiempoFormated(i->first) <<" " << tiempoNoFormated(i->second) << endl;
        }
    }
}

int main()
{
    int numero_test_case = 0;
    string fin = "";
    cin >> numero_test_case;
    forn(kk, numero_test_case)
    {
        cout << fin;
        ResolverUnCaso();
        fin = "\n";
    }
    return 0;
}
